﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;

namespace TA.Turbo
{
	internal class FileUploadRequestStream : Stream
	{
		#region PUBLIC
		#region INIT
		public FileUploadRequestStream(HttpWorkerRequest wr)
		{
			this._wr = wr;
			this._length = long.Parse(this._wr.GetKnownRequestHeader(11));
		}
		#endregion
		#region PROPS
		public override bool CanRead
		{
			get { return true; }
		}
		public override bool CanSeek
		{
			get { return false; }
		}
		public override bool CanWrite
		{
			get { return false; }
		}
		public override long Length
		{
			get { return this._length; }
		}
		public override long Position
		{
			get
			{
				return this._positionGlobal - this._size;
			}
			set
			{
				throw new NotSupportedException();
			}
		}
		#endregion
		#region METHODS
		public override void Flush()
		{
			throw new NotSupportedException();
		}
		public override int Read(byte[] buffer, int offset, int count)
		{
			count = this.Peek(buffer, offset, count);
			this.Skip(count);

			return count;
		}
		public int Peek(byte[] buffer, int offset, int count)
		{
			count = (int)Math.Min(count, this._length - this._positionGlobal + this._size);
			this.EnsureData(count);
			Array.Copy(this._buffer, this._position, buffer, offset, count);
			return count;
		}
		public void Skip(int count)
		{
			this.EnsureData(count);

			this._position += count;
			this._size -= count;
		}
		public override long Seek(long offset, SeekOrigin origin)
		{
			throw new NotSupportedException();
		}
		public override void SetLength(long value)
		{
			throw new NotSupportedException();
		}
		public override void Write(byte[] buffer, int offset, int count)
		{
			throw new NotSupportedException();
		}
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		HttpWorkerRequest _wr;
		bool _preloadedRead = false;
		byte[] _buffer = new byte[0];
		long _positionGlobal = 0, _length = 0;
		int _size = 0, _position = 0;
		#endregion
		#region PROPS
		#endregion
		#region METHODS
		private void EnsureBuffer(long freeSpaceSize)
		{
			if (this._position + this._size + freeSpaceSize > this._buffer.Length)
			{
				if (this._size + freeSpaceSize > this._buffer.Length)
				{
					byte[] old = this._buffer;
					this._buffer = new byte[this._size + freeSpaceSize + 1024];
					Array.Copy(old, this._position, this._buffer, 0, this._size);
				}
				else
				{
					Array.Copy(this._buffer, this._position, this._buffer, 0, this._size);
				}
				this._position = 0;
			}
		}
		private void EnsureData(int count)
		{
			while (this._size < count)
			{
				int read;
				if (!this._preloadedRead)
				{
					this.EnsureBuffer(this._wr.GetPreloadedEntityBodyLength());
					read = this._wr.GetPreloadedEntityBody(this._buffer, this._position);

					this._preloadedRead = true;
				}
				else
				{
					this.EnsureBuffer(count - this._size);
					read = this._wr.ReadEntityBody(this._buffer, this._position + this._size, count - this._size);
				}
				this._positionGlobal += read;
				this._size += read;
			}
		}
		#endregion
		#endregion
	}
}
